package com.cci.kangdao.task;

import com.cci.kangdao.common.RedisKeys;
import com.cci.kangdao.common.type.MarketClassType;
import com.cci.kangdao.common.type.OverTimeType;
import com.cci.kangdao.crmapi.CRMApiUtils;
import com.cci.kangdao.crmapi.CRMResponeEntity;
import com.cci.kangdao.dao.*;
import com.cci.kangdao.dao.model.UserT;
import com.cci.kangdao.redis.RedisClientUtils;
import com.cci.kangdao.service.AsyncCrmService;
import com.cci.kangdao.service.DBUMessageService;
import com.cci.kangdao.utilTool.Date_Util;
import com.cci.kangdao.utilTool.JsonUtils;
import com.cci.kangdao.utilTool.LocalTimeUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author William Du
 * @date 2019/8/28
 */
@Component
public class DBUWorkOrderTask extends BaseTask{

    private Logger log = Logger.getLogger(this.getClass().getName());

    @Resource
    private RedisClientUtils redisClientUtils;
    @Resource
    private OverTimeNotifyAreaEngineerDao overTimeNotifyAreaEngineerDao;
    @Resource
    private WorkOrderOperatorRelationDao workOrderOperatorRelationDao;
    @Autowired
    private LoginDao loginDao;
    @Resource
    private DBURemindTaskTDao dbuRemindTaskTDao;
    @Resource
    private NotifyRecordTDao notifyRecordTDao;
    @Resource
    private DBUMessageService dbuMessageService;
    @Resource
    private WorkOrderTDao workOrderTDao;
    @Resource
    private AsyncCrmService asyncCrmService;

    
    

    public void workOrderTask() {
        log.info("DBU超时工单定时任务--开始");
        // 尝试加锁
        if (!redisClientUtils.lock(RedisKeys.dbuWorkOrderScheduledKey(), 59L)) {
            // 加锁失败，说明已有程序在运行，跳出
            return;
        }
        // 获取真实时间
        String systemTime = LocalTimeUtil.getRealCurrentTime();

        /**
         * 修改时间2021-04-20
         * DBU服务工单未完成超时时间以及提醒内容
         */
        // DBU未完成工单超时提醒
        try {
            log.info("DBU未完成工单超时提醒--开始" + systemTime);

            asyncCrmService.workOrderUnfinishedOvertime(systemTime);
        } catch (Exception e) {
            log.error("DBU执行未完成工单超时任务发生异常："+e.getMessage(),e);
        }
        // 出发超时
        try {
            workOrderDepartOvertime(systemTime);
        } catch (Exception e) {
            log.error("DBU执行出发超时任务发生异常："+e.getMessage(),e);
        }
        // 维修超时（外出  到达未维修超时， 室内  未维修超时）
        try {
            workOrderRepairOverTime(systemTime);
        } catch (Exception e) {
            log.error("DBU执行维修超时任务发生异常："+e.getMessage(),e);
        }

        // DBU工单到达超时提醒
        try {
            workOrderArriveOvertime(systemTime);
        } catch (Exception e) {
            log.error("DBU执行到达超时任务发生异常："+e.getMessage(),e);
        }
        /**
         * 修改时间2021-04-20
         * DBU服务工单未完成超时时间以及提醒内容
         */
        // DBU未完成工单超时提醒
//        try {
//            workOrderUnfinishedOvertime(systemTime);
//        } catch (Exception e) {
//            log.error("DBU执行未完成工单超时任务发生异常："+e.getMessage(),e);
//        }
        // 删除锁
        redisClientUtils.delkey(RedisKeys.dbuWorkOrderScheduledKey());
        log.info("DBU超时工单定时任务-结束");
    }

    // 出发超时任务
    @Transactional
    public void workOrderDepartOvertime(String systemTime){
        List<Map<String,Object>> workOrderList = dbuRemindTaskTDao.selectWorkOrderWithNoDepart(systemTime);
        if(CollectionUtils.isNotEmpty(workOrderList)){
            // 拼装出发超时工单未通知信息列表
            List<Map<String,Object>> overTimeOrderList = new ArrayList<>();
            for(Map<String,Object> orderMap:workOrderList){
                Integer function = 0;
                Long overTime = MapUtils.getLong(orderMap,"OverTime",0L);
                // 查询超时时间大于2小时，并且小于24小时的工单（为了减少不必要数据量）
                //出发延误原因1、超时规则：90分钟未出发；2、计算规则：出发时间-技师接单时间>90分钟；版本  3.4.0
//                if(overTime >= 60*2 && overTime < 60*24){
//                ***************************
//                sprint24     改为技师出发时间-技师接单时间＞40分钟；
                if (overTime >= 40 && overTime < 60 * 24) {
                    function = 11;
                    Long orderId = org.apache.commons.collections4.MapUtils.getLong(orderMap,"ID");
                    if(!hasNotified(orderId,function)){
                        orderMap.put("Function",function);
                        overTimeOrderList.add(orderMap);
                    }
                }else{
                    // 不必要工单数据
                    continue;
                }
            }
            if(CollectionUtils.isNotEmpty(overTimeOrderList)){
                for(Map<String,Object> overTimeOrder: overTimeOrderList){
                    // 超时订单
                    Integer category = 2;
                    // 通知类型
                    Integer function = MapUtils.getInteger(overTimeOrder,"Function");
                    // 工单信息
                    Long orderId = MapUtils.getLong(overTimeOrder,"ID");
                    String orderNo = MapUtils.getString(overTimeOrder,"OrderNo");
                    Integer orderStatus = MapUtils.getInteger(overTimeOrder,"OrderStatus");
                    // 添加redis超时标记
                    setOverTimeKey(orderId,OverTimeType.TYPE4);
                    // 给区域工程师，站长/信息员，技师发送通知
                    sendMessage(category,function,orderId,orderNo,orderStatus,Boolean.TRUE,Boolean.TRUE,Boolean.TRUE);
                }
            }
        }
    }
    private void sendMessage(Integer category,Integer function,Long orderId,String orderNo,Integer orderStatus,Boolean sendAreaEngineer,Boolean sendManager, Boolean sendTechnician){
        List<Map<String,Object>> sendList = getSendList(orderId,orderStatus,sendAreaEngineer,sendManager,sendTechnician);
        if(CollectionUtils.isNotEmpty(sendList)){
            for(Map<String,Object> senderMap:sendList){
                String phone = MapUtils.getString(senderMap,"Phone");
                String username= MapUtils.getString(senderMap,"UserName");
                String userId = MapUtils.getString(senderMap,"ID");
                sendMsg(phone,orderNo,username,orderId,userId,function,category);
            }
        }
    }

    // 维修超时任务
    @Transactional
    public void workOrderRepairOverTime(String systemTime){
        List<Map<String,Object>> workOrderList = dbuRemindTaskTDao.selectWorkOrderWithNoRepair(systemTime);
        if(CollectionUtils.isNotEmpty(workOrderList)){
            // 拼装维修超时工单未通知信息列表
            List<Map<String,Object>> overTimeOrderList = new ArrayList<>();
            for(Map<String,Object> orderMap:workOrderList){
                Integer function = 0;
                Long overTime = MapUtils.getLong(orderMap,"OverTime",0L);
                // 查询超时时间大于4小时，并且小于24小时的工单（为了减少不必要数据量）
                if(overTime >= 60*4 && overTime < 60*24){
                    function = 12;
                    Long orderId = org.apache.commons.collections4.MapUtils.getLong(orderMap,"ID");
                    if(!hasNotified(orderId,function)){
                        orderMap.put("Function",function);
                        overTimeOrderList.add(orderMap);
                    }
                }else{
                    // 不必要工单数据
                    continue;
                }
            }
            if(CollectionUtils.isNotEmpty(overTimeOrderList)){
                for(Map<String,Object> overTimeOrder: overTimeOrderList){
                    // 超时订单
                    Integer category = 2;
                    // 通知类型
                    Integer function = MapUtils.getInteger(overTimeOrder,"Function");
                    // 工单信息
                    Long orderId = MapUtils.getLong(overTimeOrder,"ID");
                    String orderNo = MapUtils.getString(overTimeOrder,"OrderNo");
                    Integer orderStatus = MapUtils.getInteger(overTimeOrder,"OrderStatus");
                    // 添加redis超时标记
                    setOverTimeKey(orderId,OverTimeType.TYPE5);
                    // 给区域工程师，站长/信息员，技师发送通知
                    sendMessage(category,function,orderId,orderNo,orderStatus,Boolean.TRUE,Boolean.TRUE,Boolean.TRUE);
                }
            }
        }
    }


    @Transactional
    public void workOrderArriveOvertime(String systemTime){
        List<Map<String,Object>> workOrderList = dbuRemindTaskTDao.selectWorkOrderWithNoArrive(systemTime);
        if(CollectionUtils.isNotEmpty(workOrderList)){
            // 拼装出发超时工单未通知信息列表
            List<Map<String,Object>> overTimeOrderList = new ArrayList<>();
            for(Map<String,Object> orderMap:workOrderList){
                String estimatedTime = MapUtils.getString(orderMap,"EstimatedTime");
                String departTime = MapUtils.getString(orderMap,"DepartTime");
                // 预估时间为空，当前时间早于预估时间，预估时长为0，不做超时处理
                if(StringUtils.isEmpty(estimatedTime) || !LocalTimeUtil.isBefore(estimatedTime,systemTime) || estimatedTime.equals(departTime)){
                    continue;
                }
                Integer function = 0;
                Long overTime = MapUtils.getLong(orderMap,"OverTime",0L);
                // 查询出发时常小于72小时的工单（为了减少不必要数据量）
                if(overTime < 60*72){
                    function = 13;

                    Long orderId = org.apache.commons.collections4.MapUtils.getLong(orderMap,"ID");
                    if(!hasNotified(orderId,function)){

                        //版本号 3.4.0
//                三、到达延误原因
//                1、超时规则：以高德计算时间后延半小时未到达；
//                2、计算规则：
//                1）车用（根据“市场类型”=bus客车、truck卡车）：到达时间-出发时间①先判断是否大于两小时，是则视为超时；
//					②否则再判断到达时间-出发时间>高德推荐时间+30分钟，是则视为超时，否则不算超时；
//                2）工业（根据“市场类型”=工程机械）：到达时间-出发时间
//				    ①先判断是否大于三小时，是则视为超时；否则再判断到达时间-出发时间>高德推荐时间+30分钟，是则视为超时，否则不算超时；
//                3）非车用和工业其他类型的：到达时间-出发时间＞高德推荐时间视为超时。

//                        ****************************
//                        sprint24--------------  车用： 到达时间-出发时间>高德推荐时间+30分钟 or 到达时间-出发时间>100分钟
//                                                工业：  到达时间-出发时间>高德推荐时间+30分钟 or 到达时间-出发时间>250分钟

                        orderMap.put("Function",function);
                        String MarketType = MapUtils.getString(orderMap, "MarketType");
                        int estimatedSubdepartMinutes = Date_Util.getMinutes(
                                Date_Util.toDate(estimatedTime, "yyyy-MM-dd HH:mm:ss"),
                                Date_Util.toDate(departTime, "yyyy-MM-dd HH:mm:ss"));//预估时间  减去  出发时间

                        if (MarketClassType.BUS.equals(MarketType) || MarketClassType.TRUCK.equals(MarketType)) {
                            if (overTime > 100) { //先判断是否大于两小时，是则视为超时；
                                overTimeOrderList.add(orderMap);//有疑问
                            } else {
                                //否则再判断到达时间-出发时间>高德推荐时间+30分钟    因为是每分钟的定时，只能根据当前时间   进行判断
                                if (overTime > estimatedSubdepartMinutes + 30) {
                                    overTimeOrderList.add(orderMap);
                                }
                            }
                        } else if (MarketClassType.CONSTRUCTION.equals(MarketType)) {
//                            2）工业（根据“市场类型”=工程机械）：到达时间-出发时间
//			                            ①先判断是否大于三小时，是则视为超时；
                            if (overTime > 250) { //先判断是否大于两小时，是则视为超时；
                                overTimeOrderList.add(orderMap);//有疑问
                            } else {
                                //否则再判断到达时间-出发时间>高德推荐时间+30分钟，是则视为超时，否则不算超时；
                                if (overTime > estimatedSubdepartMinutes + 30) {
                                    overTimeOrderList.add(orderMap);
                                }
                            }
                        } else {
                            //非车用和工业其他类型的：到达时间-出发时间＞高德推荐时间视为超时。
                            if (overTime > estimatedSubdepartMinutes) {
                                overTimeOrderList.add(orderMap);
                            }
                        }
                    }
                }else{
                    // 不必要工单数据
                    continue;
                }


            }
            if(CollectionUtils.isNotEmpty(overTimeOrderList)){
                for(Map<String,Object> overTimeOrder: overTimeOrderList){

                    // 超时订单
                    Integer category = 2;
                    // 通知类型
                    Integer function = MapUtils.getInteger(overTimeOrder,"Function");
                    // 工单信息
                    Long orderId = MapUtils.getLong(overTimeOrder,"ID");
                    String orderNo = MapUtils.getString(overTimeOrder,"OrderNo");
                    Integer orderStatus = MapUtils.getInteger(overTimeOrder,"OrderStatus");
                    // 添加redis超时标记
                    setOverTimeKey(orderId,OverTimeType.TYPE6);
                    // 给站长/信息员，技师发送通知
                    sendMessage(category,function,orderId,orderNo,orderStatus,Boolean.FALSE,Boolean.TRUE,Boolean.TRUE);
                }
            }
        }
    }

    /**
     * 服务工单未完成消息提醒
     * @param systemTime
     * 此方法可以直接修改
     */
    @Transactional
    public void workOrderUnfinishedOvertime(String systemTime){
        List<Map<String,Object>> workOrderList = dbuRemindTaskTDao.selectWorkOrderWithUnfinished(systemTime);
        if(CollectionUtils.isNotEmpty(workOrderList)){
            // 拼装超时未完成工单未通知信息列表
            List<Map<String,Object>> overTimeOrderList = new ArrayList<>();
            /**
             * 修改前针对的时间段为 4、8、24、48
             * 修改后针对的时间段为4、6、12、24、48、72
             */
            for (Map<String, Object> orderMap : workOrderList) {
                Integer function = 0;
                // overTime是系统的当前时间-工单的创建时间  单位：分
                Long overTime = MapUtils.getLong(orderMap, "OverTime", 0L);


                String MarketType = MapUtils.getString(orderMap, "MarketType");
                Long orderId = MapUtils.getLong(orderMap, "ID");
                Integer orderStatus = MapUtils.getInteger(orderMap, "OrderStatus");
                //                        //版本号 3.4.0
                //                        //四、维修完成超时1、超时计算规则:
                //                        //;
                //                        //1）车用：维修完成时间-到达时间（非外出，开始维修时间）>3小时
                //                        //
                //                        //2） 工业：维修完成时间-到达时间（非外出，开始维修时间）>6小时
                //                        //
                //                        //3）其他：维修完成时间-到达时间（非外 出，开始维修时间）>12小时。。
                if (null != orderStatus && (orderStatus == 11||orderStatus == 12)) {
                    Long isOutside = MapUtils.getLong(orderMap, "IsOutside", 0L);
                    Long overTimeStatus = 0L;
                    if (isOutside == 0) {
                        String receiveTimeEngineer = MapUtils.getString(orderMap, "ReceiveTimeEngineer");
                        Date date = Date_Util.toDate(receiveTimeEngineer, "yyyy-MM-dd hh:mm");
                        //不外出的接单时间
                        overTimeStatus = Long.valueOf(Date_Util.getMinutes(date, Date_Util.toDate(LocalTimeUtil.getRealCurrentTime(), "yyyy-MM-dd hh:mm")));
                    } else if (isOutside == 1) {
                        String arriveTime = MapUtils.getString(orderMap, "ArriveTime");
                        Date date = Date_Util.toDate(arriveTime, "yyyy-MM-dd hh:mm");
                        //不外出的接单时间
                        overTimeStatus = Long.valueOf(Date_Util.getMinutes(date, Date_Util.toDate(LocalTimeUtil.getRealCurrentTime(), "yyyy-MM-dd hh:mm")));
                    }
                    if (MarketClassType.BUS.equals(MarketType) || MarketClassType.TRUCK.equals(MarketType)) {
                        if (overTimeStatus > 60 * 3) {  //车用：维修完成时间-到达时间（非外出，开始维修时间）>3小时；
                            setOverTimeKey(orderId, OverTimeType.TYPE7);
                        }
                    } else if (MarketClassType.CONSTRUCTION.equals(MarketType)) {
                        if (overTimeStatus > 390) { //工业：维修完成时间-到达时间（非外出，开始维修时间）>6小时；  sprint24改为6.5
                            setOverTimeKey(orderId, OverTimeType.TYPE7);
                        }
                    } else {
                        if (overTimeStatus > 60 * 12) {//其他：维修完成时间-到达时间（非外 出，开始维修时间）>12小时。
                            setOverTimeKey(orderId, OverTimeType.TYPE7);//需求有疑问
                        }
                    }
                }

                /**
                 *  4小时之内如果未完成，不做处理
                 */
                if(overTime < 4 * 60){
                    // 小于4小时
                    continue;
                }
                
                /**
                 *  4-6小时之内(包含4小时)时做处理
                 */
                else if(overTime >= 4 * 60 && overTime < 6 * 60){
                    // 4小时未完成
                    function = 21;
                }
                
                /**
                 *  6-12小时之内(包含6小时)时做处理
                 */
                else if(overTime >= 6 * 60 && overTime < 12 * 60){
                    // 6小时未完成
                    function = 22;
                }
                
                /**
                 *  12-24小时之内(包含12小时)时做处理
                 */
                else if(overTime >= 12 * 60 && overTime < 24 * 60){
                    // 12小时未完成
                    function = 23;
                }
                
                
                /**
	             *  24-48小时之内(包含24小时)时做处理
	             */  
                 else if (overTime >= 24 * 60 && overTime < 48 * 60) {
                    // 24小时未完成
                    function = 14;
                /**
	             *  48-72小时之内(包含48小时)时做处理
	             */
                } else if (overTime >= 48 * 60 && overTime < 72 * 60) {
                    // 48小时未完成
                    function = 15;
                } 
                
                /**
	             *  72-96小时之内(包含72小时)时做处理
	             */
                else if (overTime >= 72 * 60 && overTime < 96 * 60) {
                    // 72小时未完成
                    function = 24;
                } 
                
                else {
                    continue;
                }

                /**
                 * 2021-04-16 新的服务工单未完成超时增加了6h、12h超时时间段(同时作废了8h时间段)
                 * 校验当前服务工单是否已经发送过function类型的消息
                 * 比如
                 *	Function	21	未完成工单4小时提醒
                 *	Function	22	未完成工单6小时提醒
                 *	Function	23	未完成工单12小时提醒
                 *  Function	14	未完成工单24小时提醒
				 *	Function	15	未完成工单48小时提醒
				 *	Function	24	未完成工单72小时提醒
                 * 
                 * 
                 */
                if (!hasNotified(orderId, function)) {
                    // 未存在通知记录，发送通知
                    orderMap.put("Function", function);
                    overTimeOrderList.add(orderMap);
                }
            }
            
            /**
             * 遍历已经触发了超时时间的服务工单
             */
            if(CollectionUtils.isNotEmpty(overTimeOrderList)){
                for(Map<String,Object> overTimeOrder: overTimeOrderList){
                    // 超时订单
                    Integer category = 2;
                    // 通知类型
                    Integer function = MapUtils.getInteger(overTimeOrder,"Function");
                    // 工单信息
                    Long orderId = MapUtils.getLong(overTimeOrder,"ID");
                    String orderNo = MapUtils.getString(overTimeOrder,"OrderNo");
                    
                    // function = 14 表示：当前服务工单在24小时之内未完成服务工单
                    if(function == 14){
                        setOverTimeKey(orderId,OverTimeType.TYPE7);
                    }
                    
                    /**
                     * 根据当前服务工单查询出对应的区域工程师
                     * 在由区域工程师查询出区域工程师所关联的消息接收人(此功能在web页面进行关系绑定)
                     */
                    // 查询超时4/6/12/24/48/72小时通知人员
                    List<Map<String,Object>> sendList = getNotifyAreaEngineerList(orderId,orderNo,function,overTimeOrder);
                    // 发送相关人员
                    if(CollectionUtils.isNotEmpty(sendList)){
                        Set<String> sendSet = new HashSet<>(sendList.size());
                        for(Map<String,Object> senderMap:sendList){
                            String phone = MapUtils.getString(senderMap,"Phone");
                            String username= MapUtils.getString(senderMap,"UserName");
                            String userId = MapUtils.getString(senderMap,"ID");
                            if(sendSet.contains(phone)){
                                continue;
                            }else{
                                sendSet.add(phone);
                            }
                            sendMsgForUnfinishedWorkOrder(phone,orderNo,username,orderId,userId,function,category,overTimeOrder);
                        }
                    }
                }
            }
        }
    }

    private List<Map<String,Object>> getSendList(Long orderId, Integer orderStatus, Boolean sendAreaEngineer,Boolean sendManager, Boolean sendTechnician ) {
        Map<String, Object> queryMap = new HashMap<>(2);
        queryMap.put("orderId", orderId);
        queryMap.put("orderStatus", orderStatus);
        List<Map<String, Object>> sendList = new ArrayList<>();
        if(sendAreaEngineer){
            // 查询所属区域工程师信息
            Map<String,Object> areaEngineerMap = workOrderOperatorRelationDao.getOperatorByOrderId(orderId);
            if(MapUtils.isNotEmpty(areaEngineerMap)){
                String phone = MapUtils.getString(areaEngineerMap,"Phone");
                List<UserT> userTList = loginDao.getUserByPhone(phone);
                Map<String,Object> areaEngineerSendMap = new HashMap<>(3);
                if(CollectionUtils.isNotEmpty(userTList)){
                    areaEngineerSendMap.put("ID",userTList.get(0).getId());
                    areaEngineerSendMap.put("UserName",userTList.get(0).getUserName());
                }
                areaEngineerSendMap.put("Phone",phone);
                sendList.add(areaEngineerSendMap);
            }
        }
        if(sendManager){
            //查询服务商站长，信息员列表
            List<Map<String, Object>> stationManagerList = dbuRemindTaskTDao.selectServiceStationManagerList(queryMap);
            sendList.addAll(stationManagerList);
        }
        if(sendTechnician){
            //查询技师列表
            List<Map<String, Object>> technicianList = dbuRemindTaskTDao.selectTechnicianList(queryMap);
            sendList.addAll(technicianList);
        }
        //sprint58   多重角色的用户会发送多条短信   这块做去重
        if(CollectionUtils.isNotEmpty(sendList)){
            sendList = sendList.stream().distinct().collect(Collectors.toList());
        }
        return sendList;
    }
    
    /**
     * 保存错误的信息
     * @param overTimeOrder
     * @param function
     * @param category
     * @param exceptionInfo
     * 可以直接修改此方法
     * 
     */
    private void saveErrorNotify(Map<String,Object> overTimeOrder, int function, int category,String exceptionInfo) {
        Long orderId = MapUtils.getLong(overTimeOrder,"ID");
        String orderNo = MapUtils.getString(overTimeOrder,"OrderNo");
        
        List<Map<String,Object>> notifyList = new ArrayList<>();
        /**
         * 拼接发送的消息内容
         *  function参数说明：
	     *		Function	21	未完成工单4小时提醒
	     *		Function	22	未完成工单6小时提醒
	     *		Function	23	未完成工单12小时提醒
	     *      Function	14	未完成工单24小时提醒
		 *		Function	15	未完成工单48小时提醒
		 *		Function	24	未完成工单72小时提醒
	     *
         */
        String smsText = "";
        switch (function) {
	        case 24:
	        	// 72小时超时
	    		smsText = dbuMessageService.getUpgradeMessageForUnfinishedWorkOrder(72, overTimeOrder);
	    		break;
        	case 15:
        		// 48小时超时
        		smsText = dbuMessageService.getUpgradeMessageForUnfinishedWorkOrder(48, overTimeOrder);
        		break;
            case 14:
            	// 24小时超时
                smsText = dbuMessageService.getUpgradeMessageForUnfinishedWorkOrder(24, overTimeOrder);
                break;
            case 23:
            	// 12小时超时
	    		smsText = dbuMessageService.getUpgradeMessageForUnfinishedWorkOrder(12, overTimeOrder);
	    		break;
            case 22:
            	// 6小时超时
	    		smsText = dbuMessageService.getUpgradeMessageForUnfinishedWorkOrder(6, overTimeOrder);
	    		break;
            case 21:
            	// 4小时超时
                smsText = dbuMessageService.getUpgradeMessageForUnfinishedWorkOrder(4, overTimeOrder);
                break;
            default:
                smsText = "您有未处理工单，工单号" + orderNo + "，工单已超时，请尽快处理。";
                break;
        }

        Map<String, Object> notifyRecordTMap = new HashMap<>();
        //获取当前时间
        String currentTime = LocalTimeUtil.getRealCurrentTime();
        notifyRecordTMap.put("OrderId", orderId);
        notifyRecordTMap.put("Function", function);
        notifyRecordTMap.put("Category", category);
        // 消息内容
        notifyRecordTMap.put("Content", smsText);
        //推送方式1代表短信  2代表app推送
        notifyRecordTMap.put("SendType", 1);
        notifyRecordTMap.put("SendTime", currentTime);
        notifyRecordTMap.put("Status", 0);
        notifyRecordTMap.put("ExceptionInfo", exceptionInfo);
        notifyRecordTMap.put("IsRead", 0);
        notifyRecordTMap.put("Flag", 0);
        notifyRecordTMap.put("Creator", "");
        notifyRecordTMap.put("CreateTime", currentTime);
        notifyList.add(notifyRecordTMap);

        Map<String, Object> notifyRecordT2Map = new HashMap<>();
        notifyRecordT2Map.put("OrderId", orderId);
        notifyRecordT2Map.put("Function", function);
        notifyRecordT2Map.put("Category", category);
        // 消息内容
        notifyRecordT2Map.put("Content", smsText);
        //推送方式1代表短信  2代表app推送
        notifyRecordT2Map.put("SendType", 2);
        notifyRecordT2Map.put("SendTime", currentTime);
        notifyRecordT2Map.put("Status", 0);
        notifyRecordT2Map.put("ExceptionInfo", exceptionInfo);
        notifyRecordT2Map.put("IsRead", 0);
        notifyRecordT2Map.put("Flag", 0);
        notifyRecordT2Map.put("Creator", "");
        notifyRecordT2Map.put("CreateTime", currentTime);
        notifyList.add(notifyRecordT2Map);

        remindTaskService.saveMsgOperation(notifyList);
    }
    
    /**
     * @param orderId
     * @param orderNo
     * @param function      触发的规则
     * @param overTimeOrder 触发超时的服务工单
     * 可以直接修改此方法
     */
    public List<Map<String,Object>> getNotifyAreaEngineerList(Long orderId,String orderNo,Integer function,Map<String,Object> overTimeOrder){
    	List<Map<String,Object>> areaEngineerList = new ArrayList<>();
        /**
         * 查询出当前服务工单对应的区域工程师
         */
        Map<String,Object> areaEngineerMap = workOrderOperatorRelationDao.getOperatorByOrderId(orderId);
        Map<String, Object> workOrderMap = workOrderTDao.getOrderById(orderId);

        /**
         * 如果没有区域工程师
         * 1：保存错误信息记录
         * 2：同步工单超时到crm
         */
        if(MapUtils.isEmpty(areaEngineerMap)){
            log.error("获取未完成工单区域工程师信息异常，区域工程师信息为空，orderId：" + orderId);
            saveErrorNotify(overTimeOrder,function,2,"区域工程师信息为空");
            notifyCRM(function,overTimeOrder,new HashMap<>());
            return areaEngineerList;
        }

        String phone = MapUtils.getString(areaEngineerMap,"Phone");
        String name = MapUtils.getString(areaEngineerMap,"Name");
        String crmPositionName = org.apache.commons.collections4.MapUtils.getString(areaEngineerMap, "CrmPositionName");
        String marketType = MapUtils.getString(workOrderMap,"MarketType");
        Long channelId = MapUtils.getLong(workOrderMap,"OrderChannel");

        /**
         * 如果区域工程师手机号为空
         * 只同步工单超时信息到crm
         */
        if(StringUtils.isEmpty(phone)){
            log.error("获取工程师相关信息失败：工程师手机号为空，phone："+phone);
            notifyCRM(function,overTimeOrder,new HashMap<>());
            return areaEngineerList;
        }

        // 发送crm超时通知信息
        Map<String,Object> domainInfoMap = dbuRemindTaskTDao.getDomainInfoByPhone(phone,channelId,crmPositionName,marketType);
        if(MapUtils.isNotEmpty(domainInfoMap)){
            notifyCRM(function,overTimeOrder,domainInfoMap);
        }else {
            log.error("超时未完成工单拼装区域信息失败，查无区域信息，工程师手机号："+phone);
            notifyCRM(function,overTimeOrder,new HashMap<>());
            saveErrorNotify(overTimeOrder,function,2,"查无区域信息，工程师手机号："+phone);
        }

        /**
         * 查询出当前区域工程师所关联的消息接收人
         */
        List<Map<String,Object>> notifyEngineerListMap = overTimeNotifyAreaEngineerDao.getNotifyEngineerListByAreaEngineer(phone);
        if(CollectionUtils.isEmpty(notifyEngineerListMap)){
            log.error("获取24/48小时未完成工单通知人员信息异常，区域工程师手机号：" + phone + "；姓名：" + name);
            saveErrorNotify(overTimeOrder,function,2,"获取24/48小时未完成工单通知人员信息异常，区域工程师手机号：" + phone + "；姓名：" + name);
            return areaEngineerList;
        }
        
        /**
         * function参数说明：
         *	Function	21	未完成工单4小时提醒
         *	Function	22	未完成工单6小时提醒
         *	Function	23	未完成工单12小时提醒
         *  Function	14	未完成工单24小时提醒
		 *	Function	15	未完成工单48小时提醒
		 *	Function	24	未完成工单72小时提醒
         */
        // 根据通知类型拼装通知人员
        switch (function){
        	case 24:
        		/**
            	 * type说明：
            	 * 		type值表示当前消息接收人只接收指定超时的消息
            	 * 		比如：type=4 表示当前消息接收人，只接收4小时未完成的消息提醒
				 *         4:表示4小时未完成超时推送类型
				 *         1:表示8小时未完成超时推送类型
				 *         2:表示24小时未完成超时推送类型
				 *         3:表示48小时未完成超时推送类型
				 *         新需求后增加了几个类型
				 *         5:表示6小时未完成超时推送类型
				 *         6:表示12小时未完成超时推送类型
				 *         7:表示72小时未完成超时推送类型
            	 */
	        	// 72小时通知人员 48小时通知人员 24小时通知人员 12小时通知人员 6小时通知人员 以及 4小时通知人员
	            for (Map<String,Object> notifyEngineerMap:notifyEngineerListMap){
	                
                    Map<String,Object> twentyFourMap = new HashMap<>(5);
                    twentyFourMap.put("Contact",MapUtils.getString(notifyEngineerMap,"ProcessorName"));
                    String twentyFourPhone = MapUtils.getString(notifyEngineerMap,"ProcessorPhone");
                    /**
                     * 此块逻辑
                     * 根据手机号从User_T表中查询出用户信息
                     * 但用户在当前系统可能是不存在的，仍需要推送短信
                     */
                    if(StringUtils.isNotEmpty(twentyFourPhone)){
                        List<UserT> userTList = loginDao.getUserByPhone(twentyFourPhone);
                        if(CollectionUtils.isNotEmpty(userTList)){
                            twentyFourMap.put("ID",userTList.get(0).getId());
                            twentyFourMap.put("UserName",userTList.get(0).getUserName());
                        }
                        twentyFourMap.put("Phone",twentyFourPhone);
                        areaEngineerList.add(twentyFourMap);
                    }
	            }
	            break;
            case 15:
                // 48小时通知人员 24小时通知人员 12小时通知人员 6小时通知人员 以及 4小时通知人员
                for (Map<String,Object> notifyEngineerMap:notifyEngineerListMap){
                	
                	Integer type = MapUtils.getInteger(notifyEngineerMap,"Type");
                    if(type.equals(3) || type.equals(2) || type.equals(4) || type.equals(5) || type.equals(6)){
                        Map<String,Object> fortyEightMap = new HashMap<>(5);
                        fortyEightMap.put("Contact",MapUtils.getString(notifyEngineerMap,"ProcessorName"));
                        String fortyEightPhone = MapUtils.getString(notifyEngineerMap,"ProcessorPhone");
                        List<UserT> userT1List = loginDao.getUserByPhone(fortyEightPhone);
                        if(CollectionUtils.isNotEmpty(userT1List)){
                            fortyEightMap.put("ID",userT1List.get(0).getId());
                            fortyEightMap.put("UserName",userT1List.get(0).getUserName());
                        }
                        fortyEightMap.put("Phone",fortyEightPhone);
                        areaEngineerList.add(fortyEightMap);
                    }
                }
                break;
            case 14:
                // 24小时通知人员 12小时通知人员 6小时通知人员 以及 4小时通知人员
                for (Map<String,Object> notifyEngineerMap:notifyEngineerListMap){
                    Integer type = MapUtils.getInteger(notifyEngineerMap,"Type");
                    if(type.equals(2) || type.equals(4) || type.equals(5) || type.equals(6)){
                        Map<String,Object> twentyFourMap = new HashMap<>(5);
                        twentyFourMap.put("Contact",MapUtils.getString(notifyEngineerMap,"ProcessorName"));
                        String twentyFourPhone = MapUtils.getString(notifyEngineerMap,"ProcessorPhone");
                        if(StringUtils.isNotEmpty(twentyFourPhone)){
                            List<UserT> userTList = loginDao.getUserByPhone(twentyFourPhone);
                            if(CollectionUtils.isNotEmpty(userTList)){
                                twentyFourMap.put("ID",userTList.get(0).getId());
                                twentyFourMap.put("UserName",userTList.get(0).getUserName());
                            }
                            twentyFourMap.put("Phone",twentyFourPhone);
                            areaEngineerList.add(twentyFourMap);
                        }
                    }
                }
                break;
            case 23:
                // 12小时通知人员 6小时通知人员 以及 4小时通知人员
                for (Map<String,Object> notifyEngineerMap:notifyEngineerListMap){
                    Integer type = MapUtils.getInteger(notifyEngineerMap,"Type");
                    if(type.equals(4) || type.equals(5) || type.equals(6)){
                        Map<String,Object> fiveMap = new HashMap<>(5);
                        fiveMap.put("Contact",MapUtils.getString(notifyEngineerMap,"ProcessorName"));
                        String fivePhone = MapUtils.getString(notifyEngineerMap,"ProcessorPhone");
                        List<UserT> userT1List = loginDao.getUserByPhone(fivePhone);
                        if(CollectionUtils.isNotEmpty(userT1List)){
                            fiveMap.put("ID",userT1List.get(0).getId());
                            fiveMap.put("UserName",userT1List.get(0).getUserName());
                        }
                        fiveMap.put("Phone",fivePhone);
                        areaEngineerList.add(fiveMap);
                    }
                }
                break;   
            case 22:
                // 6小时通知人员 以及 4小时通知人员
                for (Map<String,Object> notifyEngineerMap:notifyEngineerListMap){
                    Integer type = MapUtils.getInteger(notifyEngineerMap,"Type");
                    if(type.equals(4) || type.equals(5)){
                        Map<String,Object> fiveMap = new HashMap<>(5);
                        fiveMap.put("Contact",MapUtils.getString(notifyEngineerMap,"ProcessorName"));
                        String fivePhone = MapUtils.getString(notifyEngineerMap,"ProcessorPhone");
                        List<UserT> userT1List = loginDao.getUserByPhone(fivePhone);
                        if(CollectionUtils.isNotEmpty(userT1List)){
                            fiveMap.put("ID",userT1List.get(0).getId());
                            fiveMap.put("UserName",userT1List.get(0).getUserName());
                        }
                        fiveMap.put("Phone",fivePhone);
                        areaEngineerList.add(fiveMap);
                    }
                }
                break;
            case 21:
                // 4小时通知人员
                for (Map<String,Object> notifyEngineerMap:notifyEngineerListMap){
                    Integer type = MapUtils.getInteger(notifyEngineerMap,"Type");
                    if(type.equals(4)){
                        Map<String,Object> fiveMap = new HashMap<>(5);
                        fiveMap.put("Contact",MapUtils.getString(notifyEngineerMap,"ProcessorName"));
                        String fivePhone = MapUtils.getString(notifyEngineerMap,"ProcessorPhone");
                        List<UserT> userT1List = loginDao.getUserByPhone(fivePhone);
                        if(CollectionUtils.isNotEmpty(userT1List)){
                            fiveMap.put("ID",userT1List.get(0).getId());
                            fiveMap.put("UserName",userT1List.get(0).getUserName());
                        }
                        fiveMap.put("Phone",fivePhone);
                        areaEngineerList.add(fiveMap);
                    }
                }
                break;
            default:
                break;
        }
        //去重
        if (CollectionUtils.isNotEmpty(areaEngineerList)) {
            Set<String> set = new HashSet<>();
            areaEngineerList = areaEngineerList.stream().filter(e -> {
                String phoneSet = (String) e.get("Phone");
                return set.add(phoneSet);
            }).collect(Collectors.toList());
        }
        return areaEngineerList;
    }

    private void notifyCRM(Integer function,Map<String,Object> overTimeOrder,Map<String,Object> domainInfoMap){
        Map<String, Object> getNotifyCrmMap = new HashMap<>();
        getNotifyCrmMap.put("orderNo",MapUtils.getString(overTimeOrder,"OrderNo"));
        getNotifyCrmMap.put("CRMOrderNo",MapUtils.getString(overTimeOrder,"OrderNoCrm"));
        getNotifyCrmMap.put("domainId",MapUtils.getString(domainInfoMap,"CrmPostNo",""));
        getNotifyCrmMap.put("domainName",MapUtils.getString(domainInfoMap,"CrmPositionName",""));
        getNotifyCrmMap.put("operatorName","系统");
        getNotifyCrmMap.put("operatorPhone","18501075230");
        /**
         * function参数说明：
         *	Function	21	未完成工单4小时提醒
         *	Function	22	未完成工单6小时提醒
         *	Function	23	未完成工单12小时提醒
         *  Function	14	未完成工单24小时提醒
		 *	Function	15	未完成工单48小时提醒
		 *	Function	24	未完成工单72小时提醒
         */
        switch (function){
        	case 24:
        		getNotifyCrmMap.put("timeOut","72h");
        		break;
        	case 15:
        		getNotifyCrmMap.put("timeOut","48h");
        		break;
            case 14:
                getNotifyCrmMap.put("timeOut","24h");
                break;
            case 23:
                getNotifyCrmMap.put("timeOut","12h");
                break;
            case 22:
                getNotifyCrmMap.put("timeOut","6h");
                break;
            case 21:
                getNotifyCrmMap.put("timeOut","4h");
                break;
            default:
                break;
        }
        getNotifyCrmMap.put("systemTime",LocalTimeUtil.getRealCurrentTime());
        CRMResponeEntity responseEntity = CRMApiUtils.getCRMServiceApi().syncTimeoutAccomplish("CCI", getNotifyCrmMap);
        log.info("4/6/12/24/48/72小时未完成工单通知crm返回值："+JsonUtils.toJsonString(responseEntity));
        if (responseEntity.getStatus() != 0) {
            log.error("4/6/12/24/48/72小时未完成工单通知crm失败，响应状态：" + responseEntity.getStatus() + "，响应信息:" + responseEntity.getMessage());
        }
    }

    public void setOverTimeKey(Long orderId,OverTimeType overTimeType){
        String workOrderId = String.valueOf(orderId);
        Integer code = overTimeType.getCode();
        redisClientUtils.setObject(RedisKeys.overTimeWorkOrderTypeKey(workOrderId,code), code,60*60*24*30);
    }
    
    /**
     * 根据orderId查询指定的服务工单是否已经推送过指定function的消息
     * @param orderId   服务工单id
     * @param function  表示一种超时类型 比如：4小时未完成超时、8小时未完成超时......
     * @return
     */
    public Boolean hasNotified(Long orderId,Integer function){
        Boolean notified = Boolean.TRUE;
        Map<String,Object> queryNotify = new HashMap<>();
        queryNotify.put("OrderId",orderId);
        queryNotify.put("Function",function);
        List<Map<String,Object>> notifyList =  notifyRecordTDao.selectOrderRecordList(queryNotify);
        if(CollectionUtils.isEmpty(notifyList)){
            notified = Boolean.FALSE;
        }else{
            if(function.equals(17)){
                Map<String,Object> notifyMap = notifyList.get(0);
                String createTime = MapUtils.getString(notifyMap,"CreateTime");
                long durationMinutes = LocalTimeUtil.getDurationMinutes(createTime,LocalTimeUtil.getRealCurrentTime());
                if(durationMinutes >= 24*60L){
                    notified = Boolean.FALSE;
                }
            }
        }
        return notified;
    }
}
